package org.mili.ticketeer.dao;

import org.mili.application.dao.AbstractDao;
import org.mili.application.dao.DaoException;
import org.mili.application.dao.ModificationResult;
import org.mili.application.dao.RowTransformer;
import org.mili.application.dao.query.QueryBuilder;
import org.mili.ticketeer.dto.Contact;
import org.mili.application.dto.Identifieable;
import org.mili.ticketeer.dto.SexEnum;
import org.mili.application.util.Lambda;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ContactDao extends AbstractDao {
    private Map<String, Contact> cache = new HashMap<>();

    public ContactDao() {
        super(Contact.UniqueFields.values(), Contact.Fields.values(), Contact.TABLE);
    }

    public List<Contact> getContacts() throws DaoException {
        return read(new ContactRowTransformer());
    }

    public ModificationResult write(final Contact contact) throws DaoException {
        cache.clear();
        return createOrUpdate(contact);
    }

    public Contact findByLastName(String name) throws DaoException {
        Contact contact= cache.get(name.toLowerCase());
        if (contact == null) {
            contact = (Contact) readSingle(
                    new ContactRowTransformer(),
                    QueryBuilder.createQueryBuilder()
                            .select()
                            .fields(Identifieable.Fields.ID, fields)
                            .from(table)
                            .where()
                            .eq(Contact.Fields.LASTNAME, name).build());
            cache.put(name.toLowerCase(), contact);
        }
        return contact;
    }

    public List<Contact> getSpeakersSortedByStreetAndName() throws DaoException {
        return doInDao(new Lambda<List<Contact>>() {
            @Override
            public List<Contact> exec(Object... params) throws SQLException {
                return query(new ContactRowTransformer(),
                        QueryBuilder.createQueryBuilder()
                                .select()
                                .fields(Identifieable.Fields.ID, fields)
                                .from(table)
                                .orderBy()
                                .asc(Contact.Fields.STREET)
                                .asc(Contact.Fields.NUMBER).build());
            }
        });
    }

    static class ContactRowTransformer implements RowTransformer<Contact> {
        @Override
        public Contact transform(ResultSet resultSet) throws SQLException {
            Contact contact = new Contact();
            contact.setId(resultSet.getInt(Identifieable.Fields.ID.name()));
            contact.setFirstName(resultSet.getString(Contact.Fields.FIRSTNAME.name()));
            contact.setLastName(resultSet.getString(Contact.Fields.LASTNAME.name()));
            contact.setStreet(resultSet.getString(Contact.Fields.STREET.name()));
            contact.setNumber(resultSet.getString(Contact.Fields.NUMBER.name()));
            contact.setZip(resultSet.getInt(Contact.Fields.ZIP.name()));
            contact.setSex(SexEnum.fromCode(resultSet.getString(Contact.Fields.SEX.name())));
            contact.setPhone(resultSet.getString(Contact.Fields.PHONE.name()));
            contact.setEmail(resultSet.getString(Contact.Fields.EMAIL.name()));
            contact.setToken(resultSet.getString(Contact.Fields.TOKEN.name()));
            contact.setActive(resultSet.getBoolean(Contact.Fields.ACTIVE.name()));
            contact.setSpeaker(resultSet.getBoolean(Contact.Fields.ISSPEAKER.name()));
            return contact;
        }
    }
}
